package net.studio.simpletetris.control;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import net.studio.simpletetris.intf.IBlock;
import net.studio.simpletetris.intf.IFigure;

import android.graphics.Color;

public class Figure extends Object implements IFigure {

	public static class FigureType {
		public static final int TRIADA = 0;
		public static final int LCORNER = 1;
		public static final int RCORNER = 2;
		public static final int LZIGZAG = 3;
		public static final int RZIGZAG = 4;
		public static final int STICK = 5;
		public static final int BOX = 6;
	}

	public static class FigureCorner {
		public static final int FC00 = 0;
		public static final int FC90 = 1;
		public static final int FC180 = 2;
		public static final int FC270 = 3;
	}

	public static class FigureColor extends Color {
		public static final int NAVY = 0xff000080;
		public static final int SILVER = 0xffc0c0c0;
		public static final int LIME = 0xff00ff00;
		public static final int FUCHSIA = 0xffff00ff;
		public static final int AQUA = 0xff00ffff;
	}

	public static final int MAX_BLOCK_NUM = 4;

	private static final byte[][][] figureTypes = new byte[][][] {
		
			{ 	{ 0, 1, 0, 0 }, 
				{ 1, 1, 1, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
			
			{ 	{ 1, 1, 1, 0 }, 
				{ 1, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
			
			{ 	{ 1, 1, 1, 0 }, 
				{ 0, 0, 1, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
			
			{ 	{ 1, 1, 0, 0 }, 
				{ 0, 1, 1, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
			
			{ 	{ 0, 1, 1, 0 }, 
				{ 1, 1, 0, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
			
			{ 	{ 1, 1, 1, 1 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
			
			{ 	{ 1, 1, 0, 0 }, 
				{ 1, 1, 0, 0 }, 
				{ 0, 0, 0, 0 }, 
				{ 0, 0, 0, 0 }	},
		
		};
	
	private static final int[] figureColors = new int[] { 
			FigureColor.NAVY/*,
			FigureColor.SILVER*/,
			FigureColor.RED,
			FigureColor.LIME,
			FigureColor.BLUE,
			FigureColor.FUCHSIA,
			FigureColor.AQUA,
			FigureColor.YELLOW/*,
			FigureColor.WHITE*/
		};
	
	protected List<IBlock> blocks = null;
	protected byte[][] structure = null;

	protected int x = 0;
	protected int y = 0;
	protected int color = 0;

	public Figure(int figureType, int color) {
		this(getStructure(figureType), color);
	}
	
	public Figure(byte[][] structure, int color) {
		this.blocks = new ArrayList<IBlock>();
		this.structure = new byte[structure.length][];
		for (int i = 0; i < structure.length; i++) {
			this.structure[i] = new byte[structure[i].length];
			for (int j = 0; j < structure[i].length; j++) {
				this.structure[i][j] = structure[i][j];
			}
		}
		setColor(color);
		initBlocks();
	}
	
	public static int getRandomFigureType() {
		Random randomGenerator = new Random();
		return randomGenerator.nextInt(figureTypes.length);
	}

	public static int getRandomColor() {
		Random randomGenerator = new Random();
		int index = randomGenerator.nextInt(figureColors.length);
		int result = figureColors[index];
		return result;
	}
	
	public static Figure getRandomFigure() {
		return new Figure(Figure.getRandomFigureType(), Figure.getRandomColor());
	}
	
	public Figure clone() {
		Figure figure = new Figure(structure, getColor());
		figure.setX(getX());
		figure.setY(getY());
		return figure;
	}

	public static byte[][] getStructure(int figureType) {
		if (figureType < figureTypes.length)
			return figureTypes[figureType];
		return null;
	}

	public static int getColor(int colorIndex, int defaultColor) {
		if (colorIndex < figureColors.length)
			return figureColors[colorIndex];
		return defaultColor;
	}

	public static int getColorIndex(int color) {
		for (int i = 0; i < figureColors.length; i++)
			if (figureColors[i] == color)
				return i;
		return -1;
	}

	public int getColor() {
		return color;
	}

	public void setColor(int value) {
		color = value;
	}

	public int getX() {
		return x;
	}

	public void setX(int value) {
		x = value;
	}

	public int getY() {
		return y;
	}

	public void setY(int value) {
		y = value;
	}

	public void clear() {
		blocks = new ArrayList<IBlock>();
	}

	synchronized public void initBlocks() {
		clear();
		if (this.structure == null) return;
		for (int y = 0; y < this.structure.length; y++) {
			for (int x = 0; x < this.structure[y].length; x++) {
				if (this.structure[y][x] != 0) {
					Block block = new Block(x, y, this.color);
					block.setParent(this);
					block.setColor(this.getColor());
					addBlock(block);
				}
			}
		}
	}

	synchronized public void addBlock(IBlock block) {
		blocks.add(block);
	}

	public void move(int direct) {
		switch (direct) {
		case MoveDirect.LEFT:
			setX(this.getX() - 1);
			break;
		case MoveDirect.RIGHT:
			setX(this.getX() + 1);
			break;
		case MoveDirect.DOWN:
			setY(this.getY() + 1);
			break;
		case MoveDirect.UP:
			setY(this.getY() - 1);
		}
	}

	public void rotate(int direction) {
		byte[][] tmp = new byte[this.structure.length][this.structure.length];

		int _i = 0, _j = 0;

		for (int i = 0; i < this.structure.length; i++) {
			for (int j = 0; j < this.structure.length; j++) {
				if (direction == RotateDirect.ANTICLOCKWISE) {
					_i = j;
					_j = this.structure.length - i - 1;
					tmp[i][j] = this.structure[_i][_j];
				} else {
					_j = i;
					_i = this.structure.length - j - 1;
					tmp[i][j] = this.structure[_i][_j];
				}
			}
		}

		int horizFlag = 0;
		while (0 == horizFlag) {
			for (int i = 0; i < MAX_BLOCK_NUM; i++) {
				if (tmp[0][i] > 0) {
					horizFlag = 1;
					break;
				}
			}
			if (0 == horizFlag) {
				for (int j = 0; j < MAX_BLOCK_NUM - 1; j++) {
					for (int i = 0; i < MAX_BLOCK_NUM; i++)
						tmp[j][i] = tmp[j + 1][i];
				}
				for (int j = 0; j < MAX_BLOCK_NUM; j++)
					tmp[MAX_BLOCK_NUM - 1][j] = 0;
			}
		}
		int vertFlag = 0;
		while (0 == vertFlag) {
			for (int j = 0; j < MAX_BLOCK_NUM; j++) {
				if (tmp[j][0] > 0) {
					vertFlag = 1;
					break;
				}
			}
			if (0 == vertFlag) {
				for (int j = 0; j < MAX_BLOCK_NUM; j++) {
					for (int i = 0; i < MAX_BLOCK_NUM - 1; i++)
						tmp[j][i] = tmp[j][i + 1];
				}
				for (int j = 0; j < MAX_BLOCK_NUM; j++)
					tmp[j][MAX_BLOCK_NUM - 1] = 0;
			}
		}

		for (int i = 0; i < this.structure.length; i++) {
			for (int j = 0; j < this.structure[i].length; j++) {
				this.structure[i][j] = tmp[i][j];
			}
		}

		this.initBlocks();
	}
	
	public int getWidth() {
		int result = 0;

		int[] _counter = new int[MAX_BLOCK_NUM];

		for (int i = 0; i < blocks.size(); i++) {
			_counter[blocks.get(i).getX()] += 1;
			if (_counter[blocks.get(i).getX()] == MAX_BLOCK_NUM) {
				result++;
			}
		}
		return result;
	}
	
	public int getHeight() {
		int result = 0;

		int[] counter = new int[MAX_BLOCK_NUM];

		for (int i = 0; i < blocks.size(); i++) {
			if (counter[blocks.get(i).getY()] > 0)
				continue;
			counter[blocks.get(i).getY()] += 1;
			if (counter[blocks.get(i).getY()] > 0) {
				result++;
			}
		}
		return result;
	}

	@Override
	synchronized public void removeBlock(int index) {
		this.blocks.remove(index);
	}

	@Override
	synchronized public IBlock getBlock(int index) {
		if (index < getBlockCount())
			return this.blocks.get(index);
		return null;
	}

	@Override
	synchronized public int getBlockCount() {
		return this.blocks.size();
	}

	@Override
	public int getBlockSize() {
		return 4;
	}
	
}
